require 'rubygems'
require 'rubyvis'
require './debug.rb'

module Mkuz
    
    class Reporter
        
        @@MAX_NUMBER_OF_POINTS_ON_SCATTERPLOT   = 500
        @@FLUSH_BYTES                           = 1024 * 5
        
        def initialize(path, title)
            @title = title
            @html = ""
            
            #write beginning
            html =
"<html> 
  <head>
    #{head}
  </head>
  <body>
  <h3>#{title}</h3>
"

            File.open(path, "w"){|f| f.write(html)}
            @file = File.open(path, "a")
        end
        
        def <<(content)
            convert(content)
        end
        
        def flush
            @file.write(@html)
            @html = ""
        end
        
        def close
            
            @html << 
"  </body>
</html>"
            flush
            @file.close
        end
        
        private
                
        def head

"     <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
      <title>#{@title}</title>
      <script type='text/javascript'>
        function showImage(id, path)
            {
                document.getElementById(id).innerHTML=\"<embed type='image/svg+xml' src='\"+path + \"'/><br/>\" + 
                    \"<button onclick='hideImage(\\\"\" + id + \"\\\", \\\"\" + path + \"\\\");' >Скрыть диаграмму</button>\";
            }
            function hideImage(id, path) 
            {
                document.getElementById(id).innerHTML=
                    \"<button onclick='showImage(\\\"\" + id + \"\\\", \\\"\" + path + \"\\\");' >Показать диаграмму</button>\";
            }
      </script>"
      
        end
        
        def convert(val)
            flush if @html.length > @@FLUSH_BYTES
            
            if val.kind_of?(Hash) then
                val.each{ |k,v|
                    if k == 'section' then
                        convert_to_section(v)
                    elsif k == "scatterplot" then
                        convert_to_scatterplot(v)
                    else
                        @html << "<#{k}>"
                        convert(v)
                        @html << "</#{k}"
                    end
                }
            elsif val.kind_of?(Array) then
                val.each{|v| 
                    @html << "<p>" 
                    convert(v) 
                    @html << "</p>"
                }
            else
                @html << val.to_s
            end
            @html << "\n"
        end
        
        def convert_to_section(section)
            convert(section)
            @html << "<hr><br/>\n"
        end
        
        def convert_to_scatterplot(plot)
            flush if @html.length > @@FLUSH_BYTES
            
            if File::exists? "skip_plots" then
                @html << "Построение диаграммы отменено. " 
                return
            end
            
            time_elapsed("drawing scatterplot #{plot['id']}"){
                dir_rel = plot['dir_rel']
                dir_abs = plot['dir_abs']
                samples1 = plot['x_samples']
                samples2 = plot['y_samples']
                id = plot['id']
                x_desc =   plot['x_desc']
                y_desc =   plot['y_desc']
                
                path_rel = "#{dir_rel}#{id}.svg"
                path_abs = "#{dir_abs}#{id}.svg"
                
                render_scatterplot(samples1, samples2, path_abs)
                
                plot_id = "scatterplot_#{id}"
                    
                @html <<
"<p>X - #{x_desc}, </p>
<p>Y - #{y_desc}. </p>
<p id='#{plot_id}'>
   <button onclick='showImage(\"#{plot_id}\", \"#{path_rel}\");'>Показать диаграмму</button>
</p>"
            }
            
        end
        
        def render_scatterplot(samples1, samples2, path)
            time_elapsed("rendering scatterplot to #{path}"){
            
                samples1_s = samples1.sort
                min1 = samples1_s[(samples1.size*0.05).to_i .. -1].min
                max1 = samples1_s[0 .. (samples1.size*0.95).to_i].max
                
                samples2_s = samples2.sort
                min2 = samples2_s[(samples2.size*0.05).to_i .. -1].min
                max2 = samples2_s[0 .. (samples2.size*0.95).to_i].max
                
                if min1 == max1 then
                    min1 = samples1.min
                    max1 = samples1.max
                end
                
                if min2 == max2 then
                    min2 = samples2.min
                    max2 = samples2.max
                end
                
                return if min1 == max1 || min2 == max2
                
                s1 = []
                s2 = []
                while s1.size <= @@MAX_NUMBER_OF_POINTS_ON_SCATTERPLOT do
                    index = rand(s1.size-1)
                    s1 << samples1[index]
                    s2 << samples2[index]
                end
                samples1 = s1
                samples2 = s2
                
                data = pv.range(samples1.length).map {|i| 
                    [samples1[i], samples2[i]] 
                }

                w = 420
                h = 400
                
                x = pv.Scale.linear(min1, max1).range(0, w)
                y = pv.Scale.linear(min2, max2).range(0, h)


                # The root panel.
                vis = pv.Panel.new().width(w).height(h).bottom(20).left(50).right(10).top(5);

                # Y-axis and ticks. 
                vis.add(pv.Rule).data(y.ticks()).bottom(y).strokeStyle(lambda {|d| d!=0 ? "#eee" : "#000"}).anchor("left").add(pv.Label).visible(lambda {|d| true}).text(y.tick_format)

                # X-axis and ticks. 
                vis.add(pv.Rule).data(x.ticks()).left(x).stroke_style(lambda {|d| d!=0 ? "#eee" : "#000"}).anchor("bottom").add(pv.Label).visible(lambda {|d|  true}).text(x.tick_format);

                #/* The dot plot! */
                vis.add(pv.Panel).data(data).add(pv.Dot).left(lambda {|d| x.scale(d[0])}).bottom(lambda {|d| y.scale(d[1])}).shape_size(3)


                vis.render()
                File.open(path, "w") { |f| f.write(vis.to_svg()) }
            }
        end
        
    end
    
end #module